using System;
using System.Diagnostics;
using System.IO;
using System.Xml;

namespace DbBuilder
{
	public class ScriptStep
	{
		public enum ScriptType
		{
			List, Sql, SqlCmd, Cmd, Data
		}

		private readonly XmlNode stepNode;
		public ScriptStep(XmlNode node)
		{
			stepNode = node;
		}

		public bool Execute(bool redeployableOnly)
		{
			if (redeployableOnly && stepNode.getAttribute("RedeployableCodeObject") != "1")
			{
				return true;
			}
			switch ((ScriptType) Enum.Parse(typeof (ScriptType), stepNode.Attributes["Type"].Value, true))
			{
			case ScriptType.Sql:
				return RunSQLScriptFileWithOSQL(Program.Instance.SQLServerInstanceName, stepNode);
			case ScriptType.SqlCmd:
				throw new NotImplementedException();
			case ScriptType.Cmd:
				return RunShellCommand(stepNode);
			case ScriptType.List:
				return new ScriptList(stepNode.Attributes["FileName"].Value).Execute(redeployableOnly);
			case ScriptType.Data:
				return new StaticDataStep(stepNode).Execute(redeployableOnly);
			default:
				throw new NotSupportedException();
			}
		}

		public bool RunShellCommand(XmlNode cmdStepXML)
		{
			//Get script parameters from XML
			string scriptDbName = cmdStepXML.Attributes["DBName"].Value;
			string scriptDbMappedName = Program.Instance.databaseNameMapping[scriptDbName];
			string scriptFileName = cmdStepXML.Attributes["FileName"].Value;
			string scriptDescr = cmdStepXML.Attributes["Name"].Value;
			string scriptParameters = cmdStepXML.Attributes["CommandLineParameters"].Value;
			// replace placeholders in the command line parameters
			scriptParameters = scriptParameters.Replace("%srvname%", Program.Instance.SQLServerInstanceName); // server name
			scriptParameters = scriptParameters.Replace("%dbname%", scriptDbMappedName); // db name

			Logger.WriteTrace
				("Preparing to execute shell command '" + scriptDescr + "' defined as '" + scriptFileName +
					"' with command-line parameters: '" + scriptParameters + "'");

			// Creating objects for Tracing functionality
			return ShellExecute(scriptFileName, scriptParameters);
		}

		public bool RunSQLScriptFileWithOSQL(string serverName, XmlNode SQLStepXML)
		{
			string scriptDbName = SQLStepXML.Attributes["DBName"].Value;
			string scriptDbMappedName = Program.Instance.databaseNameMapping[scriptDbName];
			string scriptFileName = SQLStepXML.Attributes["FileName"].Value;
			string scriptDescr = SQLStepXML.getAttribute("Name");
			Logger.WriteTrace("Preparing to execute SQL script '"+ scriptDescr+ "' from file '" + scriptFileName + "'");
			return RunSQLScriptFileWithOSQL(serverName, scriptDbMappedName, scriptFileName);
		}

		public static bool RunSQLScriptFileWithOSQL(string serverName, string mappedDbName, string fileName)
		{
			Logger.WriteTrace("Executing SQL script from file '" + fileName + "'");

			string parameters = string.Format
				("-e -S {0} -E -w 1024 -b -d {1} -i \"{2}\"", serverName, mappedDbName, Path.Combine(Program.Instance.config_root_folder, fileName));
			return ShellExecute("sqlcmd", parameters);
		}

		public static bool ShellExecute(string scriptFileName, string scriptParameters)
		{
			Logger.WriteTrace(string.Format("Executing command '{0} {1}'", scriptFileName, scriptParameters));

			Process proc = new Process();
			proc.StartInfo.FileName = scriptFileName;
			proc.StartInfo.Arguments = scriptParameters;
			proc.StartInfo.UseShellExecute = false;
			proc.StartInfo.RedirectStandardOutput = true;
			proc.Start();
			proc.WaitForExit(10000);

			Logger.WriteTrace("================== command output below=============================");
			Logger.WriteTrace(proc.StandardOutput.ReadToEnd());
			Logger.WriteTrace("================== command output above=============================");

			return proc.ExitCode == 0;
		}
	}
}